home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 476-500 / disk_498 / yatz / src / sound.c next >
C/C++ Source or Header  |  1992-05-06  |  13KB  |  407 lines

  1. /*
  2.    Auto: ram:cc -ps -safnps <path><file>
  3.   */
  4. /****************************   Sound.c   *********************************
  5.  
  6.     Sound is copyright (c) 1988 by Richard Lee Stockton, 21305 60th Ave W.,
  7. Mountlake Terrace, Washington 98043, 206/776-1253(voice), but may be freely
  8. distributed as long as no profit is made from its distribution or sale
  9. without my written permission. I call this concept 'FreeWare', you can
  10. call it whatcha want.
  11.  
  12.     I also include the source code, (Manx Aztec 5.0a), in the hope that it
  13. will be of benefit to someone in the Amiga programming community. Feel free
  14. to alter it at will, (but at your own risk!). I _would_ appreciate
  15. receiving a copy of whatever it may become and it is always nice to receive
  16. credit, (perhaps just a few lines of glowing tribute.^)
  17.  
  18.                Long Live Leo and All the Little Schwabies!
  19.  
  20.                      To Manufacture with Manx 5.0a
  21.  
  22.                         cc -ps -safnps Sound.c
  23.                         ln +cdb Sound.o -lc16
  24.  
  25.  
  26. **************************************************************************/
  27.  
  28. #include <exec/memory.h>
  29. #include <workbench/startup.h>
  30. #include <workbench/workbench.h>
  31. #include <workbench/icon.h>
  32. #include <libraries/dosextens.h>
  33. #include <graphics/gfxbase.h>
  34. #include <devices/audio.h>
  35. #include <string.h>
  36. #include <functions.h>
  37.  
  38. /* Less than WorkBench 1.2 need not apply. That's nobody, right? ;-> */
  39.  
  40. #define  REVISION   33L
  41.  
  42. /* We'll need 4 buffers in CHIP memory, all else in FAST, if ya got it */
  43.  
  44. long  BUFSIZE = 1024L;
  45.  
  46. /* A pretty little HELP message showing valid variable ranges */
  47.  
  48. /* Probably more GLOBALS than are required. 'C' is funny stuff. */
  49. extern struct   GfxBase       *GfxBase=NULL;
  50.        struct   IOAudio       *sound[4]={NULL,NULL,NULL,NULL};
  51.        struct   Filehandle    *sFile=NULL;
  52.        struct   FileLock      *lock=NULL, *savelock=NULL;
  53.                 long          sactual=0L, sstart=0L, vol=64L, fade=0L,
  54.                                atol(), sps=0L, cycles=1L, startvol=64L,
  55.                                endvol=64L, fadevol=0L;
  56.                 short         k=0, stereo=0, left=1, right=1, compflag=0,
  57.                                statusline=1, direct=0;
  58.                 UBYTE         sunit[4]={12,10,5,3},
  59.                                sunitL[2]={1,8}, sunitR[2]={2,4};
  60.                 BOOL          help=FALSE;
  61.                 char          *sbuffer=NULL,
  62.                                *cbuf[4]={NULL,NULL,NULL,NULL},
  63.                                *SafeAllocMem(),
  64.                                *portname[4]={"Snd0","Snd1","Snd2","Snd3"};
  65.                 USHORT         loadSound(), soundSound();
  66.                 void           cleanup();
  67.  
  68. /*********** quit, give-up, go home, finish... Neatness counts! ******/
  69.  
  70. /* void quit(qstring)
  71. char    *qstring;
  72. {
  73.    cleanup(); 
  74. }
  75. */
  76. void cleanup(qstring)
  77. char *qstring;
  78. {
  79.    if(sound[0])      /* This cleans up the audio device stuff */
  80.    {
  81.       for(k=3;k>(-1);k--)
  82.       {
  83.          if((sound[k])&&(sound[k]->ioa_Request.io_Device))
  84.             AbortIO((struct IORequest *)sound[k]);
  85.       }
  86.       if(sound[0]->ioa_Request.io_Device)
  87.          CloseDevice((struct IORequest *)sound[0]);
  88.       for(k=3;k>(-1);k--)
  89.       {
  90.          if(sound[k]->ioa_Request.io_Message.mn_ReplyPort)
  91.             DeletePort(sound[k]->ioa_Request.io_Message.mn_ReplyPort);
  92.       }
  93.       for(k=3;k>(-1);k--)
  94.       {
  95.          if(sound[k]) FreeMem(sound[k],(long)sizeof(struct IOAudio));
  96.          if(cbuf[k])  FreeMem(cbuf[k],BUFSIZE);
  97.       }
  98.       sound[0]=sound[1]=sound[2]=NULL;
  99.    }
  100.  
  101.  
  102. /* Write any message to out. May be error or could be samples/second */
  103. /* You'll be sorry if you try to Write(Output()) to WorkBench!  8-)  */
  104.  
  105.  
  106. /* Clean up everything else */
  107.  
  108.    if(sFile)            Close((BPTR)sFile); 
  109.    if(sbuffer)          FreeMem(sbuffer,sactual);
  110.    if(!sound[3])        exit();
  111.    sbuffer=NULL;   
  112.    sactual=0L; sstart=0L; savelock=NULL; sps=0L; cycles=1L;
  113.    lock=0L; k=0; stereo=0; left=1; right=1; startvol=endvol=vol=64L;
  114. }
  115.  
  116. VOID
  117. cleanupsome()
  118. {
  119.    if(sbuffer)          FreeMem(sbuffer,sactual);
  120. }
  121. /*  Don't Allocate if Low Mem - by Bryce Nesbitt  */
  122. /* Aberations by RLS. 4096 should be fudge enough */
  123.  
  124. char *SafeAllocMem(size,flags)
  125. long size, flags;
  126. {
  127.    register char *p;
  128.    
  129.    if(p=(char *)AllocMem(size,flags))
  130.       if(AvailMem(MEMF_CHIP)<4096L) {FreeMem(p,size); return(NULL);}
  131.    return(p);
  132. }
  133.  
  134.  
  135. /******** Load SoundFile 'sPath' & set cycles-sps-stereo *******/
  136.  
  137. USHORT loadSound(sPa)
  138. char    *sPa;
  139. {
  140.    struct FileInfoBlock *finfo=NULL;
  141.    struct FileLock      *lock=NULL;
  142.           long          i, j;
  143.           char          string[5], sPath[80];
  144.           short         x, y, z;
  145. /* Allocate 256 bytes as work memory */
  146.    strcpy(sPath,sPa);
  147.    if(!(sbuffer=SafeAllocMem(256L,MEMF_CLEAR|MEMF_PUBLIC)))
  148.         return (20);
  149.  
  150. /* Check for and parse IFF data in first 256 bytes of file */
  151.  
  152.    if(!(sFile=(struct Filehandle *)Open(sPath,MODE_OLDFILE)))
  153.    {
  154.       FreeMem(sbuffer,256L);
  155.       sactual=256L; 
  156.       return (20);
  157.    }
  158.    Read((BPTR)sFile,sbuffer,256L);        /* load the 1st 256 bytes */
  159.    for(sstart=0L, sps=0L, i=0L; i<252L; i+=4L)
  160.    {
  161.       strncpy(string,sbuffer+i,4);   string[4]=NULL;
  162.       if(!(strcmp(string,"VHDR")))        /* get samples per second */
  163.       {
  164.          for(j=0L;j<(long)((UBYTE)sbuffer[i+20]);j++) sps+=256L;
  165.          sps += (long)((UBYTE)sbuffer[i+21L]);
  166.          if(sbuffer[i+23L]==1) compflag=1;
  167.          if(sbuffer[i+27L]!=1)
  168.             startvol=(64L*(long)(sbuffer[i+28L]*10+sbuffer[i+29L]))/100L;
  169.       }
  170.       if(!(strcmp(string,"CHAN")))            /* Channel Assignment */
  171.       {
  172.          if((sbuffer[i+7L]==6)||(sbuffer[i+11L]==6)) stereo=1;
  173.       }
  174.       if(!(strcmp(string,"BODY")))        /* get size of sound data */
  175.       {
  176.          for(j=0L;j<4L;j++)
  177.             sactual+=(((long)((UBYTE)sbuffer[i+7L-j]))<<(8L*j));
  178.          sstart = i+8L; i=252L;
  179.       }
  180.    }
  181.  
  182.  
  183.    FreeMem(sbuffer,256L); sbuffer=NULL;
  184.  
  185. /* Allocate memory for SOUND data. */
  186. /* Later we'll transfer in BUFSIZE chunks to contiguous CHIP memory. */
  187.  
  188.    if(AvailMem(MEMF_LARGEST)<(sactual+16384L)) direct=1;
  189.    if(direct) return(0);
  190.    if(!(sbuffer=SafeAllocMem(sactual,MEMF_CLEAR|MEMF_PUBLIC)))
  191.         return (20);
  192.  
  193. /* Load the data into sbuffer */
  194.  
  195.    Seek((BPTR)sFile,sstart,OFFSET_BEGINNING);
  196.    if((Read((BPTR)sFile,sbuffer,sactual)) == -1L) 
  197.      return (20);
  198.    Close((BPTR)sFile);  sFile=NULL;
  199.    return (0);
  200.  
  201. }
  202.  
  203.  
  204. /*****************  make a noise ******************/
  205.  
  206. USHORT soundSound()
  207. {
  208.     ULONG   class;
  209.     LONG    h, i, j, dactual, dlength, remaining;
  210.     USHORT  code, count;
  211.     short   z;
  212.  
  213. /* Make sure we have valid values before 'sounding' */
  214.  
  215.     if(left==right) left=right=1;
  216.     if((sps<56L)||(sps>65534L)) sps=10000L;
  217.     if((startvol<1L)||(startvol>64L)) startvol=64L;
  218.     vol=startvol;
  219.     if((endvol<1L)||(endvol>64L)) endvol=64L;
  220.     if(direct)
  221.     {
  222.        BUFSIZE=AvailMem(MEMF_CHIP|MEMF_LARGEST)/6L;
  223.        if(BUFSIZE>64000L) BUFSIZE=64000L;
  224.        BUFSIZE-=(BUFSIZE%8L);
  225.     }
  226.  
  227.     cycles = 1;
  228. /* Put up a 'status' window on the top line. */
  229.  
  230. /* Allocate sound data buffers from CHIP memory. Ports and */
  231. /* Audio Request Structures do NOT require CHIP memory */
  232.  
  233.    for(k=0;k<4;k++)
  234.    {
  235.      if(!(cbuf[k]=SafeAllocMem(BUFSIZE,
  236.            MEMF_CHIP|MEMF_CLEAR|MEMF_PUBLIC))) 
  237.            return (20);
  238.      if(!(sound[k]=(struct IOAudio *)SafeAllocMem((long)sizeof(struct IOAudio),
  239.                      MEMF_CLEAR|MEMF_PUBLIC))) 
  240.                      return (20);
  241.      if(!(sound[k]->ioa_Request.io_Message.mn_ReplyPort =
  242.                   CreatePort(portname[k],0L))) 
  243.                      return (20);
  244.    }
  245.  
  246. /* Open Audio using the first IOAudio as the 'initializer' request */
  247.  
  248.    sound[0]->ioa_Request.io_Message.mn_Node.ln_Pri = 114;
  249.    if(!right) sound[0]->ioa_Data   = &sunitL[0];
  250.    else if(!left) sound[0]->ioa_Data   = &sunitR[0];
  251.    else sound[0]->ioa_Data   = &sunit[0];
  252.    sound[0]->ioa_Length = 4L;
  253.    if((OpenDevice(AUDIONAME,0L,(struct IORequest *)sound[0],0L))!=NULL)
  254.    {
  255.       sound[0]->ioa_Request.io_Device=NULL;  /* don't AbortIO if no open */
  256.       return (20);
  257.    }
  258.  
  259. /* Set all IOAudios. */
  260.  
  261.    for(k=0;k<4;k++)
  262.    {
  263.       sound[k]->ioa_Request.io_Message.mn_Node.ln_Pri = 114;
  264.       sound[k]->ioa_Request.io_Command = CMD_WRITE;
  265.       sound[k]->ioa_Request.io_Flags   = ADIOF_PERVOL;
  266.  
  267. /* Note copies of Device & AllocKey from initializer. */
  268.  
  269.       sound[k]->ioa_Request.io_Device  = sound[0]->ioa_Request.io_Device;
  270.       sound[k]->ioa_AllocKey  = sound[0]->ioa_AllocKey;
  271.  
  272. /* Each IOAudio has its own CHIP buffer, Port, and Unit (left/right) */
  273.  
  274.       sound[k]->ioa_Data   = (UBYTE *)cbuf[k];
  275.  
  276. /* 3579547 divided by 55 = 65083, nearly the maximum Period (65535)  */
  277. /* changing this 'magic' number is all we need to make it 'European' */
  278.  
  279.       if(GfxBase->DisplayFlags&PAL) sound[k]->ioa_Period=3546895L/sps;
  280.                                else sound[k]->ioa_Period=3579547L/sps;
  281.  
  282. /* allow for volume setting. gives us effect possibilities in a script */
  283.  
  284.       sound[k]->ioa_Volume = startvol;
  285.  
  286. /* One time through this BUFSIZE (or smaller) part of the whole */
  287.  
  288.       sound[k]->ioa_Cycles = 1L;
  289.    }
  290.  
  291. /* The compiler wants 'Unit' to be a structure, we just want to mask */
  292. /* into the allocated left/right channels. left=1 or 8, right=2 or 4 */
  293. /*        ...zap! You're a Unit structure! Feel any different?       */
  294.  
  295.    for(k=2;k>(-1);k-=2)
  296.    {
  297.       if(right) sound[k+1]->ioa_Request.io_Unit = (struct Unit *)
  298.                       ((ULONG)(sound[0]->ioa_Request.io_Unit)&6L);
  299.       if(left)    sound[k]->ioa_Request.io_Unit  = (struct Unit *)
  300.                       ((ULONG)(sound[0]->ioa_Request.io_Unit)&9L);
  301.    }
  302.  
  303. /* If in STEREO, split file. If in MONO, 'b' buffers use 'a' data */
  304.  
  305.    if(stereo) remaining=(sactual/2L)-(sactual&1L);
  306.    else
  307.    {
  308.       remaining=sactual;
  309.       sound[1]->ioa_Data   = (UBYTE *)cbuf[0];
  310.       sound[3]->ioa_Data   = (UBYTE *)cbuf[2];
  311.    }
  312.  
  313. /* dactual is the length of one channel's complete data */
  314.  
  315.    dactual=remaining;     k=count=0;
  316.  
  317. /* if DIRECT_FROM_DISK, start at the beginning of the sample */
  318.  
  319.  
  320. /* we be doing loops here */
  321.  
  322.    do
  323.    {
  324.  
  325. /* be CERTAIN ioa_Length is an even number & set datalength */
  326.  
  327.       if(remaining>BUFSIZE) dlength=BUFSIZE;
  328.       else {dlength=remaining; dlength-=(dlength&1L);}
  329.  
  330. /* Move the data into the proper CHIP buffer of BUFSIZE */
  331.  
  332.     movmem(sbuffer+(dactual-remaining),cbuf[k],(int)dlength);
  333.  
  334. /* Don't load or use the right CHIP buffers if MONO. Saves time. */
  335.  
  336.       if(stereo)
  337.          movmem(sbuffer+(sactual-remaining),cbuf[k+1],(int)dlength);
  338.  
  339. /* Data has been moved, so adjust 'remaining' */
  340.  
  341.       remaining-=dlength;
  342.  
  343. /* Left and Right Lengths are the same, no matter what! */
  344.  
  345.       sound[k]->ioa_Length = sound[k+1]->ioa_Length = dlength;
  346.  
  347. /* Start one set of Left/Right Channels. */
  348.  
  349.       if(left)  BeginIO((struct IORequest *)sound[k]);
  350.       if(right) BeginIO((struct IORequest *)sound[k+1]);
  351.  
  352.  
  353. /* Is this the last time AND the last cycle? If yes & no, reset. */
  354.  
  355.       if(remaining<2L)
  356.       {
  357.          cycles--;
  358.          if(cycles!=0L)
  359.          {
  360.             if(direct) Seek((BPTR)sFile,sstart,OFFSET_BEGINNING);
  361.             remaining=dactual; dlength=BUFSIZE;
  362.             if(fadevol!=0L)
  363.             {
  364.                vol=vol+fadevol;
  365.             }
  366.          }
  367.       }
  368.       if(vol>64L) vol=64L;  if(vol<1L) vol=1L;
  369.       for(i=0L;(i<4L)&&(vol>=0L);i++) sound[i]->ioa_Volume = vol;
  370.  
  371. /* Is this the last time, or what? */
  372.  
  373.       if(remaining<2L)
  374.          WaitIO((struct IORequest *)sound[k+right]); /* wait for LAST request */
  375.       else
  376.       {
  377.          if(k) k=0; else k=2;    /* switch buffers & wait for PREVIOUS */
  378.          if(count++) WaitIO((struct IORequest *)sound[k+right]);
  379.       }
  380.  
  381. /* Keep going until we run out of data */
  382.  
  383.    }   while(remaining>1L); 
  384.       for(k=3;k>(-1);k--)
  385.       {
  386.          if((sound[k])&&(sound[k]->ioa_Request.io_Device))
  387.             AbortIO((struct IORequest *)sound[k]);
  388.       }
  389.       if(sound[0]->ioa_Request.io_Device)
  390.          CloseDevice((struct IORequest *)sound[0]);
  391.       for(k=3;k>(-1);k--)
  392.       {
  393.          if(sound[k]->ioa_Request.io_Message.mn_ReplyPort)
  394.             DeletePort(sound[k]->ioa_Request.io_Message.mn_ReplyPort);
  395.       }
  396.       for(k=3;k>(-1);k--)
  397.       {
  398.          if(sound[k]) FreeMem(sound[k],(long)sizeof(struct IOAudio));
  399.          if(cbuf[k])  FreeMem(cbuf[k],BUFSIZE);
  400.       }
  401.       sound[0]=sound[1]=sound[2]=NULL;
  402.       return (0);
  403. }
  404.  
  405.  
  406. /************************** end of Sound.c ******************************/
  407.